package fenetres;

import modules.*;
import annotation.Menu;
import interfaces.*;
import plugins.jTreeFolder.NodeWithFile;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.lang.reflect.Method;
import java.util.List;

/**
 * Cette Classe rassemble les differentes composantes de l'application (Plugins, menus et actions)
 * Elle agit comme un controleur.
 * @author Amine HALLILI amine.hallili@gmail.com
 *
 */
public class FenetreGenerale extends JFrame implements ActionListener {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	private JMenuBar                   menuBarre;
	private JMenu                      fichier,plugins,classes;
	private JMenuItem                  save,importer,classe1,runPlugins;
	private JPanel                     panelCentral,pCentre;
	//private JFileChooser             parc;
	private Dimension       	 	   d;
	private JScrollPane                scrollExplorer,scrollCentre;// element gauche(Jtree) et droit(repertoire) de la fenetre
	private Rectangle                  de;
	private List<Class<?>>       	   l;  // contient la list des classes (Plugins) chargées
	private List<IPlugin>			   iPlugins;// contient la liste de tous les plugins
	private List<PluginInterface>      pi; // contient la liste des plugins de traitement de fichier 
	private List<RepertoireInterface>  lri;// contient la liste des plugins de type Repertoire.
	private RepertoireInterface        ri; // contient un plugin pardéfaut de creation de repertoire valide
	private TreeInterface              ti; // contient un plugin pardéfaut de creatoin d'arborescence valide
	private JTree                      tree; // explorateur recuperer par un plugin 
	private final File   			   f = new File("../Plugin/bin");
	private Timer					   t;
	
	/**
	 * Constructeur de la fenetre générale permettant l'initialisation de l'application 
	 * et le chargement des plugin 
	 * <br>ainsi qu'écouter le dossier plugin pour mettre l'application à jour
	 */
	public FenetreGenerale()
	{		
		super("Explorateur JAVA 1.0");
		
		// Progress Bar : Progrès du chargement de l'application
					LoadProgress lp = new LoadProgress(100);
					lp.setVisible(true);
					lp.progress(0,"initialisation des composantes !");
		//***********************************************************
		
		
		d = Toolkit.getDefaultToolkit().getScreenSize();
		this.setBounds((d.width/2)-500, (d.height/2)-350, 1000, 700);
		de = this.getBounds();
		de.width = 180;
		
		panelCentral    = new JPanel();
		pCentre 		= new JPanel();
		scrollExplorer  = new JScrollPane();
		scrollCentre    = new JScrollPane();
		
		pCentre.setLayout(new BorderLayout());
		panelCentral.setLayout(new BorderLayout());
		scrollCentre.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));// ajoute une marge
		
		scrollExplorer.setPreferredSize(de.getSize());
		scrollCentre.setPreferredSize(new Dimension(700,de.height));
		
		menuBarre = new JMenuBar();
			fichier   = new JMenu("fichier");
				save       = new JMenuItem("sauvegarder");
				save.addActionListener(this);
				importer   = new JMenuItem("importer");
				importer.addActionListener(this);
				runPlugins = new JMenuItem("lancer");
				runPlugins.addActionListener(this);
			fichier.add(save);
			fichier.add(importer);
			fichier.add(runPlugins);
		
			plugins   = new JMenu("plugins");
			
			classes   = new JMenu("classes");
				classe1 = new JMenuItem("classe (default)");
			classes.add(classe1);
			
		// progresser la barre
		lp.progress(10,"chargement des classes depuis :"+f.getAbsolutePath());
		//***********************************************************
			
		// chargement des classes	
		if (!f.exists()) {
			System.err.println(f+" does not exist");
			System.exit(1);
		}
		
		Repository<Object> rep = new Repository<Object>(f, Object.class);
		l = rep.load();
		System.out.println(l.size()+" classe(s) loaded");
		//*********************************************************************
			
		// progresser la barre
		lp.progress(20,"chargement des plugins");
		//***********************************************************
			
			
		// Sauvegarde des plugins	
			
		iPlugins = Traitement.chargerAllPlugins(l);
		for(IPlugin c : iPlugins)
			buildMenu(c);
		
		pi = Traitement.chargerPlugins(l);
		
		
		ri = Traitement.chargerRepertoire(l);
		if(ri == null)
			pCentre.add(new JLabel("Aucun plugin de type Repertoire !"),BorderLayout.CENTER);
		else
		{
			lri = Traitement.chargerRepertoirePlugins(l);
			createRepertoireList(pCentre, lri);
		}
			
		// progresser la barre
		lp.progress(40,"création de l'arbre");
		//***********************************************************	
			
		ti = Traitement.chargerExplorateur(l);

		if(ti == null)
			scrollExplorer.getViewport().add(new JLabel("Aucun plugin de type Explorateur !"));
		else
		{
			tree = ti.getTree();	
			scrollExplorer.getViewport().add(tree);
			addListenerToTree(tree);
		}
		//***********************************************************************	
		
		// progresser la barre
		lp.progress(60,"initialisation des menus");
		//***********************************************************
			
		menuBarre.add(fichier);
		menuBarre.add(plugins);
		menuBarre.add(classes);
		
		scrollCentre.getViewport().add(pCentre);
		
		panelCentral.add(scrollExplorer,BorderLayout.WEST);
		panelCentral.add(scrollCentre,BorderLayout.CENTER);
		
		this.setContentPane(panelCentral);
		this.setJMenuBar(menuBarre);
		
		addWindowListenerWithOptions(this);
		
		// progresser la barre
		lp.progress(80,"chargement de la dernière sauvegarde");
		//***********************************************************	
		
		if(new File("Explorateur.properties").exists() && new File("tree.mem").exists())
		if(JOptionPane.showConfirmDialog(null, "Voulez vous charger la dernière sauvegarde ?") == 0)
		{
			if(new File("Explorateur.properties").exists())
				Traitement.chargerFenetre(this);
				
			if(new File("tree.mem").exists())
			{
				tree = null;
				if(ti != null)
				{
					scrollExplorer.getViewport().removeAll();
					tree = ti.loadTree();
					scrollExplorer.getViewport().add(tree);
					scrollExplorer.getViewport().validate();
					addListenerToTree(tree);
				}
			}
			
			if(ri != null)
				ri.loadOpenedFile();
				
		}
		
		loadNewPlugins(f);
		
		// progresser la barre
		lp.progress(100,"fin de chargement !");
		//***********************************************************
		this.setVisible(true);
	
	}
	
	


	/**
	 * crée le menu associé au plugin "c" passé en parametre
	 * elle se base sur l'annotaton pour creer le menu sinon elle utilise le nom de la fonction annotée
	 * si non elle utilise le nom de la classe
	 * @param c IPlugin un plugin
	 */
	void buildMenu(final IPlugin c)  {  
		
		Method[] m = c.getClass().getDeclaredMethods(); 
		JMenuItem item=null;
		boolean test = false;
			
		for(int j=0; j<m.length ; j++)
		{
			Menu menu = m[j].getAnnotation(Menu.class);
			if(menu != null)
			{
				test = true;
				if(menu.libelle() == null)
				{
					item = new JMenuItem(m[j].getName());
				}
				else
				{
					item = new JMenuItem(menu.libelle());
				}
			}
		}
		if(!test) 
		{
			String name = c.getClass().getName();
			int index = c.getClass().getName().lastIndexOf(".");
			item = new JMenuItem(name.substring(index+1, name.length()));
		}
		plugins.add(item);	
		item.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				
				final JPanel pDetail = new JPanel();
				pDetail.setLayout(new BorderLayout(2,2));
				pDetail.add(c.getFrameDetail(),BorderLayout.CENTER);
			
				if(!c.isDefault())
				{
					JButton defaut = new JButton("mettre par defaut");
					defaut.setPreferredSize(new Dimension(40,20));
					pDetail.add(defaut,BorderLayout.NORTH);
					defaut.addActionListener(new ActionListener() {
						
						@Override
						public void actionPerformed(ActionEvent arg0) {
							
							setiPlugins(Traitement.setDefaut(c, iPlugins));
							setPi(Traitement.setDefaut(c, getPi()));
							for(PluginInterface iii :getPi())
								if(iii.getClass().getName().equals(c.getClass().getName()))
									iii.setDefault(true);
								
							pCentre.add(ri.getFrame(ri.getlastOpenedDir(),getPi()),BorderLayout.CENTER);
							pCentre.validate();
							((JButton)arg0.getSource()).setVisible(false);
							
							pDetail.removeAll();
							pDetail.add(c.getFrameDetail(),BorderLayout.CENTER);
						}
					});
				}	
				JOptionPane.showMessageDialog(null, pDetail);
			}
		});	
	} 

	
	/**
	 * pour creer la liste de differents type d'affichage
	 * @param p JPanel le panel qui affiche le repertoire
	 * @param l liste des plugins de type repertoire trouvés dans le dossier Plugin/bin
	 */
	public void createRepertoireList(final JPanel p, final List<RepertoireInterface> lcr)
	{
		JComboBox list = new JComboBox();
		p.removeAll();
		
		final JPanel jp   = new JPanel();
		JPanel j    = new JPanel();
		JLabel jl   = new JLabel("Type d'affichage : ");
		
		j.setPreferredSize(new Dimension(220,25));
		jp.setPreferredSize(new Dimension(300,25));
		j.setLayout(new GridLayout());
		j.add(jl);
		j.add(list);
		jp.setLayout(new BorderLayout());
		jp.add(j, BorderLayout.EAST);
		p.add(jp, BorderLayout.NORTH);
		p.validate();	
		
		
		
		for(RepertoireInterface i :lcr)
			list.addItem(i.getTypeAffichage());
		
		
		list.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent item) {
				for(RepertoireInterface i :lcr)
				{
					
					JComboBox cb = (JComboBox)item.getSource();
					if(i.getTypeAffichage().equals((String)cb.getSelectedItem()))
					{
						p.removeAll();
						// on memorise le dernier dossier ouvert
						File lastDir = getRi().getlastOpenedDir();
						// on change le type d'affichage
						setRi(i);
						
						// on applique le nouveau type d'affichage à l'application
						p.add(jp, BorderLayout.NORTH);
						p.add(getRi().getFrame(lastDir, getPi()),BorderLayout.CENTER);
						
						p.validate();	
						
					}
				}
			}
		});		
	}
	
	
	
	/**
	 * permet la sauvegarde ou l'importation de l'application
	 */
	public void actionPerformed(ActionEvent arg0) {		
		if(arg0.getSource().equals(this.save) )
		{
			Traitement.sauvegarderFenetre(this);
			if(ri != null)
				ri.saveOpenedFiles();
			if(ti != null)
				ti.saveTree();
		}
		
		if(arg0.getSource().equals(this.importer) )
		{
			scrollExplorer.getViewport().remove(tree);
			tree = ti.loadTree();
			scrollExplorer.getViewport().add(tree);
			scrollExplorer.getViewport().validate();
			if(new File("Explorateur.properties").exists());
				Traitement.chargerFenetre(this);
			if(ri != null)
				ri.loadOpenedFile();
		}	
	}


	/**
	 * Ecoute les changements du dossier plugin 
	 * met à jour l'application
	 * @param f File fichier à écouter
	 */
	private void loadNewPlugins (final File f)
	  {
		t = new Timer(500, new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
		
				Repository<Object> rep = new Repository<Object>(f, Object.class);
				l = rep.load();
				List<IPlugin> nouvPlugins = Traitement.chargerAllPlugins(l);
				if(nouvPlugins.size() != getiPlugins().size())
				{
					setiPlugins(nouvPlugins);
					final JFrame pop = new JFrame("Mise à jour plugin");
					JPanel p = new JPanel();
					JLabel l   = new JLabel("    Des plugins ont été ajoutés ou supprimés. Chargement en cours ... !");
					JButton b  = new JButton("Fermer");
					b.setPreferredSize(new Dimension(80,20));
					b.addActionListener(new ActionListener() {
						
						@Override
						public void actionPerformed(ActionEvent arg0) {
							pop.dispose();
						}
					});
					p.setBorder(BorderFactory.createLineBorder(Color.black));
					pop.setBounds(getX()+getWidth()-405, getY()+getHeight()-65, 400, 60);
					pop.setUndecorated(true);
					
					p.setBackground(Color.yellow);
					p.add(l);
					p.add(b);
					pop.setFocusable(true);
					pop.setAlwaysOnTop(true);
					
					pop.setContentPane(p);
					pop.setVisible(true);
					
					// verification du repertoire
					if(ri == null)
					{
						System.out.println("verification de repertoire ...");
						ri=Traitement.chargerRepertoire(getL());
						if(ri != null)
						{
							setLri(Traitement.chargerRepertoirePlugins(getL()));
							createRepertoireList(pCentre, getLri());
							scrollCentre.getViewport().add(ri.getFrame(null, Traitement.chargerPlugins(getL())));
							addListenerToTree(tree);
						}
					}
					else
					{
						if(Traitement.chargerRepertoire(getL()) == null)
						{
							scrollCentre.getViewport().add(new JLabel("Aucun plugin de type Repertoire !"));
							ri = null;
							setLri(null);
						}
					}
					//******************************************************************************************
					
					// verification de l'explorateur
					if(ti == null)
					{
						
						if(Traitement.chargerExplorateur(getL()) != null)
						{
							ti = Traitement.chargerExplorateur(getL());
							tree = ti.getTree();
							scrollExplorer.getViewport().add(tree);
							addListenerToTree(tree);
						}
						else
							scrollExplorer.getViewport().add(new JLabel("Aucun plugin de type Explorateur !"));
					}
					else
					{
						if(Traitement.chargerExplorateur(getL()) == null)
						{
							scrollExplorer.getViewport().add(new JLabel("Aucun plugin de type Explorateur !"));
							ti =null;
						}
					}
					//*******************************************************************************************
					
					// creation des menus des nouveaux plugins
					getPlugins().removeAll();
					for(IPlugin c : Traitement.chargerAllPlugins(getL()))
						buildMenu(c);
					getPlugins().doClick();					
				}
			}
				
			
		});
		
		t.start();
	  }  
	

	/**
	 * met un windowListener pour ajouter l'option de sauvegarde lors de la fermeture
	 * @param fen fenetre générale
	 */
	void addWindowListenerWithOptions(FenetreGenerale fen)
	{
		fen.addWindowListener(new WindowAdapter(){
			  public void windowClosing(WindowEvent we){
				  
				  int rep = JOptionPane.showConfirmDialog(null, "Voulez vous sauvegarder","Quitter",JOptionPane.YES_NO_OPTION);
				  if(rep == 0 || rep == 1)
				  {
					  if(rep == 0)
					  {
						  Traitement.sauvegarderFenetre((FenetreGenerale)we.getSource());
						  if(ti != null)
							  ti.saveTree();
						  if(ri != null)
							  ri.saveOpenedFiles();
					  }
					  t.stop();
					  dispose();
					  System.exit(0);
				  }
			  }
			  });
	}
	
	
	
	/**
	 * ajoute un mouseListener sur le JTree en fonction de la presence du repertoire
	 * @param t JTree
	 */
	void addListenerToTree(JTree t)
	{
		if(ri == null)
			scrollCentre.getViewport().add(new JLabel("Aucun plugin de type Repertoire !"));
		else
		{
			t.addMouseListener(new MouseListener() {
				
				@Override
				public void mouseReleased(MouseEvent arg0) {}
				
				@Override
				public void mousePressed(MouseEvent arg0) {}
				
				@Override
				public void mouseExited(MouseEvent arg0) {}
				
				@Override
				public void mouseEntered(MouseEvent arg0) {}
				
				@Override
				public void mouseClicked(MouseEvent arg0) {
					if(ti.getLastPath() !=null)
					{
						// creation du repertoire avec le dernier dossier selectionné dans le jtree
						scrollCentre.getViewport().removeAll();
						pCentre.removeAll();
						createRepertoireList(pCentre, getLri());
						pCentre.add(ri.getFrame(( (NodeWithFile)(ti.getLastPath().getPath().getLastPathComponent())).getFile(), getPi()),BorderLayout.CENTER);
						scrollCentre.getViewport().add(pCentre);
						pCentre.validate();
						scrollCentre.getViewport().validate();
						
					}
				}
			});
		}
	}
	

	
	// Getters and Setters
	public JMenuBar getMenuBarre() {
		return menuBarre;
	}


	public void setMenuBarre(JMenuBar menuBarre) {
		this.menuBarre = menuBarre;
	}


	public JMenu getFichier() {
		return fichier;
	}


	public void setFichier(JMenu fichier) {
		this.fichier = fichier;
	}


	public JMenu getPlugins() {
		return plugins;
	}


	public void setPlugins(JMenu plugins) {
		this.plugins = plugins;
	}


	public JMenu getClasses() {
		return classes;
	}


	public void setClasses(JMenu classes) {
		this.classes = classes;
	}


	public JMenuItem getSave() {
		return save;
	}


	public void setSave(JMenuItem save) {
		this.save = save;
	}


	public JMenuItem getImporter() {
		return importer;
	}


	public void setImporter(JMenuItem importer) {
		this.importer = importer;
	}


	public JMenuItem getClasse1() {
		return classe1;
	}


	public void setClasse1(JMenuItem classe1) {
		this.classe1 = classe1;
	}


	public JMenuItem getRunPlugins() {
		return runPlugins;
	}


	public void setRunPlugins(JMenuItem runPlugins) {
		this.runPlugins = runPlugins;
	}


	public JPanel getPanelCentral() {
		return panelCentral;
	}


	public void setPanelCentral(JPanel panelCentral) {
		this.panelCentral = panelCentral;
	}


	public Dimension getD() {
		return d;
	}


	public void setD(Dimension d) {
		this.d = d;
	}


	public JScrollPane getScrollExplorer() {
		return scrollExplorer;
	}


	public void setScrollExplorer(JScrollPane scrollExplorer) {
		this.scrollExplorer = scrollExplorer;
	}


	public JScrollPane getScrollCentre() {
		return scrollCentre;
	}


	public void setScrollCentre(JScrollPane scrollCentre) {
		this.scrollCentre = scrollCentre;
	}


	public Rectangle getDe() {
		return de;
	}


	public void setDe(Rectangle de) {
		this.de = de;
	}


	public List<Class<?>> getL() {
		return l;
	}


	public void setL(List<Class<?>> l) {
		this.l = l;
	}


	public List<PluginInterface> getPi() {
		return pi;
	}


	public void setPi(List<PluginInterface> pi) {
		this.pi = pi;
	}


	public RepertoireInterface getRi() {
		return ri;
	}


	public void setRi(RepertoireInterface ri) {
		this.ri = ri;
	}
	
	
	public List<RepertoireInterface> getLri() {
		return lri;
	}


	public void setLri(List<RepertoireInterface> lri) {
		this.lri = lri;
	}


	public TreeInterface getTi() {
		return ti;
	}


	public void setTi(TreeInterface ti) {
		this.ti = ti;
	}


	public JTree getTree() {
		return tree;
	}


	public void setTree(JTree tree) {
		this.tree = tree;
	}


	public static long getSerialversionuid() {
		return serialVersionUID;
	}


	public JPanel getpCentre() {
		return pCentre;
	}


	public void setpCentre(JPanel pCentre) {
		this.pCentre = pCentre;
	}


	public List<IPlugin> getiPlugins() {
		return iPlugins;
	}


	public void setiPlugins(List<IPlugin> iPlugins) {
		this.iPlugins = iPlugins;
	}
	
	// *******************************************************************
}
